#include <stdlib.h>
#include <stdio.h>
#include <alsa/asoundlib.h>
#include <signal.h>
static int recording;

void stop_record(int param)
{
recording = 0;
}
void InitCapture(snd_pcm_t ** handle,snd_pcm_hw_params_t ** params,snd_pcm_uframes_t* frames,char ** buffer,int* size)
{
	int ret;
	unsigned int val;
	int dir;
	//打开设备
	ret = snd_pcm_open(handle, "default", SND_PCM_STREAM_CAPTURE, 0);
	printf("after open file\n");
	if (ret < 0)
	{
	fprintf(stderr, "unable to open device:%s\n", snd_strerror(ret));
	exit(1);
	}
	//分配一个硬件参数结构体
	snd_pcm_hw_params_alloca(params);

	//使用默认参数
	snd_pcm_hw_params_any(*handle, *params);

	//翻译
	snd_pcm_hw_params_set_access(*handle, *params, SND_PCM_ACCESS_RW_INTERLEAVED);

	//S16小端
	snd_pcm_hw_params_set_format(*handle, *params, SND_PCM_FORMAT_S16_LE);

	//双通道，立体声
	snd_pcm_hw_params_set_channels(*handle, *params, 2);

	//采样率
	val = 16000;
	snd_pcm_hw_params_set_rate_near(*handle, *params,&val,&dir);

	*frames = 32;
	snd_pcm_hw_params_set_period_size_near(*handle, *params,frames,&dir);

	//参数生效
	ret = snd_pcm_hw_params(*handle, *params);
	if (ret<0)
	{
		fprintf(stderr, "unable to set hw parameters:%s\n", snd_strerror(ret));
			exit(1);
	}
	//得到一个周期的数据大小
	snd_pcm_hw_params_get_period_size(*params, frames, &dir);

	//16位双通道，16位为2字节，2字节*2通道=4，假如frames=1024，则size是1024*4 = 4096
	*size = *frames * 4;
	*buffer = (char*)malloc(*size); 

	//设置一个周期的时间长度
	snd_pcm_hw_params_get_period_time(*params, &val, &dir);
}

void CaptureAudio(snd_pcm_t ** handle,snd_pcm_uframes_t* frames,char ** buffer,int* size,FILE ** pFile)
{
	int ret;

	recording = 1;
	while (recording)
	{
		ret = snd_pcm_readi(*handle, *buffer,*frames);
		if (ret == -EPIPE )
		{
			fprintf(stderr, "overrun occurred\n");
			snd_pcm_prepare(*handle);
		}
		else if (ret < 0)
		{
			fprintf(stderr, "error from read\n");
			snd_strerror(ret);
		}
		else if (ret != (int)(*frames))
		{
			fprintf(stderr, "short read %d frames\n",ret);
		}
		printf("write to file......%d\n", *size);
		//写到标准输出中去
		ret = fwrite(*buffer, sizeof(char), *size, *pFile);
		if (ret != *size)
		{
			fprintf(stderr, "short write :write %d bytes\n", ret);
		}
		if (signal(SIGINT, stop_record)==SIG_ERR)
		{
			fprintf(stderr, "signal failed\n");
		}
	}
}

void CloseCaptureDevice(FILE ** pFile,snd_pcm_t ** handle,char ** buffer)
{
	printf("write file exit\n");
	snd_pcm_drain(*handle);
	snd_pcm_close(*handle);
	free(*buffer);
	fclose(*pFile);
}


//执行命令是可以的 aplay -f S16_LE -c 2 -r 44100 ./test.pcm
//编译的时候 gcc -o test_record ./test_record.c -lasound
int main()
{
	FILE * pFile;
	pFile = fopen("test.pcm", "wb");
	int size;
	//给文件操作分配一个句柄
	snd_pcm_t * handle;
	//硬件参数
	snd_pcm_hw_params_t * params;
	//
	snd_pcm_uframes_t frames;
	char * buffer;
	printf("before open file\n");
	InitCapture(&handle,&params,&frames,&buffer,&size);
	CaptureAudio(&handle,&frames,&buffer,&size,&pFile);
	CloseCaptureDevice(&pFile,&handle,&buffer);
	printf("write file exit\n");

return 0;
}
